From 0db7ba8cf1e81a1192b10e07f770fb5adb4fce59 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Nov 2016 11:10:31 -0800 Subject: [PATCH] Fix recursion in build_path_deps We were slightly too eager to follow pointers! Closes #3330 --- src/cargo/core/resolver/encode.rs | 13 +++++--- tests/path.rs | 55 +++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/cargo/core/resolver/encode.rs b/src/cargo/core/resolver/encode.rs index b0c6e280a..0b35ed5c3 100644 --- a/src/cargo/core/resolver/encode.rs +++ b/src/cargo/core/resolver/encode.rs @@ -172,26 +172,28 @@ fn build_path_deps(ws: &Workspace) -> HashMap { }).collect::>(); let mut ret = HashMap::new(); + let mut visited = HashSet::new(); for member in members.iter() { ret.insert(member.package_id().name().to_string(), member.package_id().source_id().clone()); + visited.insert(member.package_id().source_id().clone()); } for member in members.iter() { - build(member, ws.config(), &mut ret); + build(member, ws.config(), &mut ret, &mut visited); } return ret; fn build(pkg: &Package, config: &Config, - ret: &mut HashMap) { + ret: &mut HashMap, + visited: &mut HashSet) { let replace = pkg.manifest().replace(); let deps = pkg.dependencies() .iter() .chain(replace.iter().map(|p| &p.1)) - .filter(|d| !ret.contains_key(d.name())) .map(|d| d.source_id()) - .filter(|id| id.is_path()) + .filter(|id| !visited.contains(id) && id.is_path()) .filter_map(|id| id.url().to_file_path().ok()) .map(|path| path.join("Cargo.toml")) .filter_map(|path| Package::for_path(&path, config).ok()) @@ -199,7 +201,8 @@ fn build_path_deps(ws: &Workspace) -> HashMap { for pkg in deps { ret.insert(pkg.name().to_string(), pkg.package_id().source_id().clone()); - build(&pkg, config, ret); + visited.insert(pkg.package_id().source_id().clone()); + build(&pkg, config, ret, visited); } } } diff --git a/tests/path.rs b/tests/path.rs index 7d057ae75..f13cd9d3c 100644 --- a/tests/path.rs +++ b/tests/path.rs @@ -9,6 +9,7 @@ use cargo::util::process; use cargotest::sleep_ms; use cargotest::support::paths::{self, CargoPathExt}; use cargotest::support::{project, execs, main_file}; +use cargotest::support::registry::Package; use hamcrest::{assert_that, existing_file}; #[test] @@ -924,3 +925,57 @@ Caused by: [..] (os error [..]) ")); } + +#[test] +fn invalid_path_dep_in_workspace_with_lockfile() { + Package::new("bar", "1.0.0").publish(); + + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "top" + version = "0.5.0" + authors = [] + + [workspace] + + [dependencies] + foo = { path = "foo" } + "#) + .file("src/lib.rs", "") + .file("foo/Cargo.toml", r#" + [project] + name = "foo" + version = "0.5.0" + authors = [] + + [dependencies] + bar = "*" + "#) + .file("foo/src/lib.rs", ""); + p.build(); + + // Generate a lock file + assert_that(p.cargo("build"), execs().with_status(0)); + + // Change the dependency on `bar` to an invalid path + File::create(&p.root().join("foo/Cargo.toml")).unwrap().write_all(br#" + [project] + name = "foo" + version = "0.5.0" + authors = [] + + [dependencies] + bar = { path = "" } + "#).unwrap(); + + // Make sure we get a nice error. In the past this actually stack + // overflowed! + assert_that(p.cargo("build"), + execs().with_status(101) + .with_stderr("\ +error: no matching package named `bar` found (required by `foo`) +location searched: [..] +version required: * +")); +} -- 2.30.2